﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ITAP.ShprossesBuilder.Modelling.Components;
using ITAP.ShprossesBuilder.Modelling;
using ITAP.ShprossesBuilder.Editor;
using System.Drawing;
using ITAP.ShprossesBuilder.Calculations;
using ITAP.ShprossesBuilder.Properties;
using ITAP.Core.Modelling;
using ITAP.Core.Calculations;

namespace ITAP.ShprossesBuilder.Operations
{
    public class OperationAlignSelectedShprossesRelativeToComponentAndModel : IOperation
    {
        private ModelControl modelControl;
        #region IOperation Members

        public string Name
        {
            get { return "Выровнять компоненты по первому компоненту и краям модели"; }
        }

        public OperationGroup OperationGroup
        {
            get { return OperationGroup.Other; }
        }

        public System.Drawing.Image Thumbnail
        {
            get { return Resources.AlignRelativeToComponentAndModel.ToBitmap(); }
        }

        public void Execute(ModelControl modelControl)
        {
            this.modelControl = modelControl;
            if (modelControl.ModelContainer.SelectedComponentsStack.Count <= 1)
                return;

            ContextMenuStrip menuStrip = new ContextMenuStrip();

            EventHandler handler = new EventHandler(OnItemClick);
            ToolStripItem right = new ToolStripMenuItem("Вправо", null, handler);
            right.Tag = OffsetTo.Right;
            menuStrip.Items.Add(right);
            ToolStripItem up = new ToolStripMenuItem("Вверх", null, handler);
            up.Tag = OffsetTo.Up;
            menuStrip.Items.Add(up);
            ToolStripItem left = new ToolStripMenuItem("Влево", null, handler);
            left.Tag = OffsetTo.Left;
            menuStrip.Items.Add(left);
            ToolStripItem down = new ToolStripMenuItem("Вниз", null, handler);
            down.Tag = OffsetTo.Down;
            menuStrip.Items.Add(down);

            menuStrip.Show(Cursor.Position);

        }

        private void OnItemClick(object sender, EventArgs e)
        {
            ToolStripItem item = sender as ToolStripItem;
            OffsetTo offset = (OffsetTo)item.Tag;

            IComponent mainComponent = modelControl.ModelContainer.SelectedComponentsStack[0];

            ModelPoint mainPoint = null;
            if (mainComponent is ShprossConnector)
                mainPoint = mainComponent.Position;
            else if (mainComponent is Shpross)
                mainPoint = (mainComponent as Shpross).SelectedPointPosition;


            AlignRelativeToForm form = new AlignRelativeToForm();
            if (form.ShowDialog() != DialogResult.OK)
                return;
            
            double totalLength = 0;

            Model model = mainComponent.Parent as Model;
            RectangleF modelRect = model.BoundingBox;

            switch (offset)
            {
                case OffsetTo.Right:
                    totalLength =
                        ModelCalculations.GetDistance(mainPoint, new ModelPoint(modelRect.X + modelRect.Width, mainPoint.Y));
                    break;
                case OffsetTo.Up:
                    totalLength =
                        ModelCalculations.GetDistance(mainPoint, new ModelPoint(mainPoint.X, modelRect.Y + modelRect.Height));
                    break;
                case OffsetTo.Left:
                    totalLength =
                        ModelCalculations.GetDistance(mainPoint, new ModelPoint(modelRect.X, mainPoint.Y));
                    break;
                case OffsetTo.Down:
                    totalLength =
                        ModelCalculations.GetDistance(mainPoint, new ModelPoint(mainPoint.X, modelRect.Y));
                    break;
            }

            if (form.Align == AlignRelative.ToInnerModelSize)
            {
                totalLength = totalLength - model.SpacerWidth;
            }

            int counter = 0;
            List<IComponent> componentsToAlign = new List<IComponent>();
                
            for (int i = 1; i < modelControl.ModelContainer.SelectedComponentsStack.Count; i++)
            {
                IComponent selectedComponent = modelControl.ModelContainer.SelectedComponentsStack[i];
                if (selectedComponent is ShprossConnector)
                {
                    componentsToAlign.Add(selectedComponent);
                    counter++;
                }
                else if (selectedComponent is Shpross)
                {
                    Shpross shpross = selectedComponent as Shpross;
                    if (shpross.SelectedPoint == ShprossPoints.Start || shpross.SelectedPoint == ShprossPoints.Center ||
                        shpross.SelectedPoint == ShprossPoints.End)
                    {
                        componentsToAlign.Add(selectedComponent);
                        counter++;
                    }
                }
            }

            for (int i = 0; i < componentsToAlign.Count; i++)
            {
                IComponent selectedComponent = componentsToAlign[i];

                ModelPoint moveToPoint;

                if (selectedComponent is ShprossConnector)
                {
                    moveToPoint = this.GetMoveToPoint(mainPoint, selectedComponent.Position, offset, totalLength, counter, i);
                    selectedComponent.MoveTo(moveToPoint, selectedComponent.Parent.BoundingBox);
                }
                else if (selectedComponent is Shpross)
                {
                    Shpross shpross = selectedComponent as Shpross;
                    if (shpross.SelectedPoint == ShprossPoints.Start)
                    {
                        moveToPoint = this.GetMoveToPoint(mainPoint, shpross.StartPoint, offset, totalLength, counter, i);
                        shpross.MoveStartPointTo(moveToPoint, selectedComponent.Parent.BoundingBox, false);
                    }
                    else if (shpross.SelectedPoint == ShprossPoints.End)
                    {
                        moveToPoint = this.GetMoveToPoint(mainPoint, shpross.EndPoint, offset, totalLength, counter, i);
                        shpross.MoveEndPointTo(moveToPoint, selectedComponent.Parent.BoundingBox, false);
                    }
                    else if (shpross.SelectedPoint == ShprossPoints.Center)
                    {
                        moveToPoint = this.GetMoveToPoint(mainPoint, shpross.Position, offset, totalLength, counter, i);
                        shpross.MoveTo(moveToPoint, selectedComponent.Parent.BoundingBox);
                    }
                }
            }

            this.modelControl.UpdateModel();
        }

        public bool CanUndo
        {
            get { return true; }
        }

        #endregion


        private ModelPoint GetMoveToPoint(ModelPoint source, ModelPoint componentPoint, OffsetTo offset, double totalLength, 
            int componentsCount, int currentComponentIter)
        {
            ModelVector vector = null;
            double offsetValue = totalLength * (currentComponentIter + 1) / (componentsCount + 1);
            switch (offset)
            {
                case OffsetTo.Right:
                    vector = new ModelVector(offsetValue, 0);
                    break;
                case OffsetTo.Up:
                    vector = new ModelVector(0, offsetValue);
                    break;
                case OffsetTo.Left:
                    vector = new ModelVector(-offsetValue, 0);
                    break;
                case OffsetTo.Down:
                    vector = new ModelVector(0, -offsetValue);
                    break;
            }
            ModelPoint result = ModelCalculations.GetOffsetPoint(source, vector);
            if (offset == OffsetTo.Left || offset == OffsetTo.Right)
            {
                result.Y = componentPoint.Y;
            }
            else if(offset == OffsetTo.Up || offset == OffsetTo.Down)
            {
                result.X = componentPoint.X;
            }
            
            return result;
        }

    }
}
